Skip to content

feat(openfeature): preserve configuration source semantics - #9413

Closed
leoromanovsky wants to merge 15 commits into
leo.romanovsky/ffl-2697-nodejs-agentless-configuration-sourcefrom
leo.romanovsky/ffl-2697-nodejs-configuration-contract
Closed

feat(openfeature): preserve configuration source semantics#9413
leoromanovsky wants to merge 15 commits into
leo.romanovsky/ffl-2697-nodejs-agentless-configuration-sourcefrom
leo.romanovsky/ffl-2697-nodejs-configuration-contract

Conversation

@leoromanovsky

@leoromanovsky leoromanovsky commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Motivation

Until now, Node.js customers could activate the Datadog OpenFeature provider only by setting DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED=true. That experimental input did more than enable a provider: the implementation it unlocked subscribed to the Agent's FFE_FLAGS Remote Configuration product. Customers who set it therefore adopted Feature Flags with Remote Configuration's Agent connectivity, network path, and delivery assumptions.

The new configuration model makes CDN-backed agentless delivery the default for new customers so they no longer need an experimental opt-in. We cannot reinterpret the existing legacy opt-in as agentless, however, because that would silently move an established customer to a different delivery system. During the migration window, explicit legacy true must remain on Remote Configuration, explicit legacy false must remain disabled, and only an absent legacy value may receive the new agentless default.

This also has a billing boundary. Requests to Remote Configuration and the CDN are billing surfaces, so "agentless is the default" cannot mean that installing or initializing the tracer starts polling. The migration separates the concerns previously collapsed into the experimental switch: DD_FEATURE_FLAGS_ENABLED is the global kill switch, DD_FEATURE_FLAGS_CONFIGURATION_SOURCE chooses a delivery system when explicit, and application access to tracer.openfeature activates default agentless polling. This PR implements that precedence on top of sealed #9397 without creating phantom traffic or breaking the existing RC cohort.

flowchart TD
  Start["Tracer starts"] --> Enabled{"DD_FEATURE_FLAGS_ENABLED"}
  Enabled -->|"false"| Disabled["Provider disabled<br/>No RC subscription<br/>No CDN polling"]
  Enabled -->|"true or unset"| Explicit{"Explicit configuration source?"}
  Explicit -->|"remote_config"| RC["Eager FFE_FLAGS subscription"]
  Explicit -->|"agentless"| Wait["Wait for application provider access"]
  Explicit -->|"unsupported offline or invalid"| Closed["Fail closed<br/>No network delivery"]
  Explicit -->|"absent"| Legacy{"Legacy experimental variable?"}
  Legacy -->|"true"| RC
  Legacy -->|"false"| Disabled
  Legacy -->|"absent"| Wait
  Wait --> Access["Application accesses tracer.openfeature"]
  Access --> CDN["Start CDN-backed polling"]
Loading

Changes

Separate enablement from source selection. The resolver now returns an enabled state independently from the selected source. A disabled provider has no synthetic disabled source; enabled configurations select only agentless or remote_config.

Apply the compatibility precedence once. Global false wins first, an explicit supported source wins next, and the legacy variable is consulted only when the new source is absent. The result is fixed for the lifetime of the tracer.

Activate only the selected delivery path. Explicit and grandfathered Remote Configuration remain eager. The provider, exposure writer, Agent strategy probe, and agentless poller remain lazy until application access to tracer.openfeature. Invalid input, including reserved offline, fails closed without RC or CDN traffic.

Preserve migration observability. Existing configuration-origin reporting remains intact so legacy usage can be measured during the migration window.

Decisions

The kill switch is absolute. DD_FEATURE_FLAGS_ENABLED=false disables the provider and prevents both CDN polling and the FFE_FLAGS subscription. true merely permits source resolution.

Existing customers stay on Remote Configuration. With no explicit new source, legacy true preserves RC and legacy false preserves disabled behavior. Only customers with no legacy value receive the new default.

Agentless is the default, not startup traffic. New customers default to agentless, but polling begins only after application provider access. An explicit agentless or remote_config selection still overrides the legacy value.

Only two sources are supported today. agentless and remote_config are valid. offline is reserved for future startup-provided UFC bytes and currently fails closed; it is not the disable switch.

Validation

No-Agent dogfooding proof

The exact Node.js head 94a16dc3017bf63056561645521a47a5ef625e93 was packaged with the repository's npm pack-based dogfooding helper and mounted into the Node app from ffe-dogfooding head c2ca5be1ae59d7ef083ef731957881d23f95ff00. The resulting dd-trace@7.0.0-pre artifact had SHA-256 d36448abe2708a56dadc3b9dc190500330e6d80e3144a04479293f17478689c3.

The isolated Compose graph rendered only:

mock-intake
app-nodejs
evaluator

datadog-agent was absent from both the rendered graph and running services. Container inspection also confirmed that DD_FEATURE_FLAGS_CONFIGURATION_SOURCE, DD_FEATURE_FLAGS_ENABLED, and DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED were all absent. FFE_ACTIVATE_PROVIDER_ON_STARTUP=false kept the application on the pre-access side of the billing boundary.

APP_URL=http://localhost:38083 \
MOCK_INTAKE_URL=http://localhost:38090 \
scripts/validate-configuration-source-activation.sh nodejs starts-after-activation

Result: PASS: tracer startup was silent and provider access started agentless delivery.

Observation Evidence
Before application access providerActivated=false, providerState=PROVIDER_NOT_READY, and configuration_requests_total=0 after the validator's three-second silence window.
After /activate-provider providerActivated=true, providerState=PROVIDER_READY, and the first configuration request reached /api/v2/feature-flagging/config/rules-based/server.
Direct application evaluation ffe-dogfooding-string-flag returned dogfood-treatment with reason TARGETING_MATCH.
Evaluator health GET /health returned {"status":"healthy"}.
Dogfooding dashboard result GET /api/latest-results reported Node.js status=success, variant=dogfood-treatment, evaluation_reason=TARGETING_MATCH, and provider_state=PROVIDER_READY at 2026-07-21T03:30:18Z.

This run also found a dogfooding-harness mismatch before product validation: the local mock returned raw UFC while the CDN contract and tracer require a JSON:API universal-flag-configuration envelope. The same fixture was wrapped in that envelope for the proof run; apps/mock-intake still passed go test ./.... No tracer code was changed for the correction, and the temporary harness/Compose edits were removed after the isolated stack was torn down.

Cross-repository system-tests proof

The exact Node.js head 94a16dc3017bf63056561645521a47a5ef625e93 was validated against merged system-tests main at 54649784b2d2807522ebeaabae49ffe70e921014 (DataDog/system-tests#7332).

binaries/nodejs-load-from-local mounted the local dd-trace-js-node-configuration-contract worktree, whose checked-out head was the signed Node.js commit above. The freshly rebuilt parametric environment exercised 19 source/enablement cases plus the slow-poller concurrency boundary.

PYTEST_XDIST_AUTO_NUM_WORKERS=12 TEST_LIBRARY=nodejs ./run.sh PARAMETRIC \
  -F tests/parametric/test_ffe/test_configuration_sources.py::Test_Feature_Flag_Configuration_Source_Selection \
  -F tests/parametric/test_ffe/test_configuration_sources.py::Test_Feature_Flag_Configuration_Source_Poller_Concurrency::test_delayed_no_overlap \
  tests/parametric/test_ffe/test_configuration_sources.py::Test_Feature_Flag_Configuration_Source_Selection \
  tests/parametric/test_ffe/test_configuration_sources.py::Test_Feature_Flag_Configuration_Source_Poller_Concurrency::test_delayed_no_overlap

Result: 20 passed in 25.92s.

The focused registration regression test passed 7/7 and proves tracer initialization does not initialize the OpenFeature module before provider access. The complete OpenFeature unit suite passed 229/229, and the OpenFeature integration suite passed 5/5.

Case Proven behavior
Explicit remote_config Loads and acknowledges UFC, evaluates the expected value, advertises the FFE_FLAGS capability/product, and sends zero CDN requests.
Global false with explicit RC Suppresses the RC capability/product and sends zero CDN requests.
RC with no payload Crosses the provider-access boundary without falling back to CDN.
Absent, empty, or whitespace source with no legacy value Sends zero Feature Flags traffic and advertises no RC capability at startup; after /ffe/start, evaluates the expected value and sends the authenticated request to the expected CDN path.
Stable true with no source Preserves lazy default-agentless behavior instead of selecting RC.
Absent, empty, or whitespace source plus legacy true Preserves Remote Configuration and sends zero CDN requests.
Global false with legacy true The stable kill switch wins and suppresses both delivery paths.
Absent, empty, or whitespace source plus legacy false Disables both delivery paths.
Explicit agentless plus legacy true Explicit source wins; CDN starts only after provider access and RC remains off.
Explicit RC plus legacy false Explicit source wins; RC is used and CDN remains off.
Global false with default agentless Provider access cannot start CDN polling and RC remains off.
Invalid source Fails closed with both delivery paths silent.
Reserved offline input Remains unsupported and fails closed with both delivery paths silent, independently from an arbitrary invalid value.
Slow agentless response A 1.5-second response against a 1-second poll interval produces repeated poll opportunities while max_in_flight == 1, proving requests do not overlap.

Define source selection, managed and custom endpoint derivation, staging and GovCloud routing, and bounded timing semantics. Keep this policy layer independent from transport and provider activation, with focused resolver tests.
Fetch one authenticated UFC snapshot with the runtime transport, suppress tracer instrumentation, validate the JSON:API resource, and only advance last-known-good state after successful application. Cover gzip, ETags, malformed payloads, and custom endpoints alongside the loader.
Turn snapshot loading into a fixed-delay lifecycle with bounded retries, independent timeouts, overlap prevention, rate-limited warnings, TLS-aware credential handling, and idempotent shutdown. Exercise timing, failure, and cancellation boundaries with fake timers.
Expose the configuration surface, attach the selected source to the provider lifecycle, and keep Agent Remote Configuration behind explicit opt-in. Pair the activation path with fleet-wide config, provider, shutdown, and packaged-application tests.
@dd-octo-sts

dd-octo-sts Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Overall package size

Self size: 6.8 MB
Deduped: 7.46 MB
No deduping: 7.46 MB

Dependency sizes | name | version | self size | total size | |------|---------|-----------|------------| | import-in-the-middle | 3.3.2 | 124.41 kB | 440.65 kB | | opentracing | 0.14.7 | 194.81 kB | 194.81 kB | | dc-polyfill | 0.1.11 | 25.74 kB | 25.74 kB |

🤖 This report was automatically generated by heaviest-objects-in-the-universe

@datadog-official

datadog-official Bot commented Jul 17, 2026

Copy link
Copy Markdown

Tests

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

🔄 Datadog retried 1 test - 1 passed on retry View in Datadog

🎯 Code Coverage (details)
Patch Coverage: 100.00%
Overall Coverage: 96.89% (-1.53%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 94a16dc | Docs | Datadog PR Page | Give us feedback!

@codecov

codecov Bot commented Jul 17, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.92%. Comparing base (053684d) to head (94a16dc).
⚠️ Report is 2 commits behind head on leo.romanovsky/ffl-2697-nodejs-agentless-configuration-source.

Additional details and impacted files
@@                                        Coverage Diff                                        @@
##           leo.romanovsky/ffl-2697-nodejs-agentless-configuration-source    #9413      +/-   ##
=================================================================================================
- Coverage                                                          98.35%   96.92%   -1.43%     
=================================================================================================
  Files                                                                927      926       -1     
  Lines                                                             123669   123703      +34     
  Branches                                                           10629    21513   +10884     
=================================================================================================
- Hits                                                              121637   119905    -1732     
- Misses                                                              2032     3798    +1766     
Flag Coverage Δ
aiguard 53.70% <71.29%> (-4.52%) ⬇️
aiguard-integration 57.13% <71.29%> (+0.05%) ⬆️
apm-bucket-0 53.93% <71.29%> (-4.55%) ⬇️
apm-bucket-1 58.87% <71.29%> (-5.69%) ⬇️
apm-bucket-2 58.12% <71.29%> (-5.50%) ⬇️
apm-bucket-3 55.51% <71.29%> (-5.41%) ⬇️
apm-capabilities-tracing 60.63% <72.22%> (-1.67%) ⬇️
apm-integrations-aerospike 53.09% <71.29%> (-4.53%) ⬇️
apm-integrations-confluentinc-kafka-javascript 57.21% <71.29%> (-5.26%) ⬇️
apm-integrations-couchbase 53.42% <71.29%> (-4.48%) ⬇️
apm-integrations-http 58.06% <71.29%> (-5.55%) ⬇️
apm-integrations-kafkajs 57.85% <71.29%> (-5.22%) ⬇️
apm-integrations-next 54.31% <71.29%> (-5.70%) ⬇️
apm-integrations-prisma 54.30% <71.29%> (-5.14%) ⬇️
appsec 68.79% <71.29%> (-5.09%) ⬇️
appsec-express_fastify_graphql 65.69% <71.29%> (-5.78%) ⬇️
appsec-integration 51.97% <71.29%> (+0.06%) ⬆️
appsec-kafka_ldapjs_lodash 59.18% <71.29%> (-5.61%) ⬇️
appsec-mongodb-core_mongoose_mysql 62.38% <71.29%> (-6.12%) ⬇️
appsec-next 52.90% <71.29%> (-5.28%) ⬇️
appsec-node-serialize_passport_postgres 62.03% <71.29%> (-6.17%) ⬇️
appsec-sourcing_stripe_template 60.43% <71.29%> (-6.08%) ⬇️
debugger 65.67% <80.55%> (-0.16%) ⬇️
instrumentations-bucket-0 48.97% <71.29%> (-3.46%) ⬇️
instrumentations-bucket-1 55.12% <71.29%> (-5.98%) ⬇️
instrumentations-bucket-10 56.73% <71.29%> (-6.23%) ⬇️
instrumentations-bucket-11 48.97% <71.29%> (-3.47%) ⬇️
instrumentations-bucket-12 49.14% <71.29%> (-3.75%) ⬇️
instrumentations-bucket-13 48.91% <71.29%> (-3.48%) ⬇️
instrumentations-bucket-2 50.10% <71.29%> (-4.25%) ⬇️
instrumentations-bucket-3 54.04% <71.29%> (-6.04%) ⬇️
instrumentations-bucket-4 49.38% <71.29%> (-3.64%) ⬇️
instrumentations-bucket-5 53.19% <71.29%> (-5.13%) ⬇️
instrumentations-bucket-6 55.76% <71.29%> (-5.90%) ⬇️
instrumentations-bucket-7 53.68% <71.29%> (-5.54%) ⬇️
instrumentations-bucket-8 54.80% <71.29%> (-5.68%) ⬇️
instrumentations-bucket-9 56.22% <71.29%> (-6.12%) ⬇️
instrumentations-instrumentation-couchbase 48.38% <71.29%> (-3.57%) ⬇️
instrumentations-integration-esbuild 34.06% <32.00%> (-0.01%) ⬇️
llmobs-ai_anthropic_bedrock 57.79% <71.29%> (-5.51%) ⬇️
llmobs-bucket-1 57.12% <71.29%> (-5.48%) ⬇️
llmobs-openai 57.53% <71.29%> (-5.74%) ⬇️
llmobs-sdk 60.08% <71.29%> (-5.29%) ⬇️
llmobs-vertex-ai 54.36% <71.29%> (-5.60%) ⬇️
master-coverage ?
openfeature 55.47% <89.81%> (+0.06%) ⬆️
openfeature-unit 50.88% <100.00%> (-3.34%) ⬇️
platform-core_esbuild_instrumentations-misc 38.63% <71.29%> (-2.10%) ⬇️
platform-integration 62.32% <74.07%> (+0.04%) ⬆️
platform-shimmer_unit-guardrails_webpack 37.43% <71.29%> (-1.98%) ⬇️
plugins-bucket-0 53.30% <71.29%> (-4.46%) ⬇️
plugins-bucket-1 55.22% <71.29%> (+0.06%) ⬆️
plugins-bucket-11 57.65% <71.29%> (-5.05%) ⬇️
plugins-bucket-17 ?
plugins-bucket-18 57.18% <71.29%> (-6.39%) ⬇️
plugins-bucket-19 55.50% <71.29%> (-7.00%) ⬇️
plugins-bucket-20 57.69% <71.29%> (-9.06%) ⬇️
plugins-bucket-4 53.92% <71.29%> (-5.47%) ⬇️
plugins-bullmq_cassandra_cookie 57.49% <71.29%> (-5.16%) ⬇️
plugins-cookie-parser_crypto_dd-trace-api 52.49% <71.29%> (-5.08%) ⬇️
plugins-fetch_fs_generic-pool 54.64% <71.29%> (-5.03%) ⬇️
plugins-google-cloud-pubsub_grpc_handlebars 59.92% <71.29%> (-5.71%) ⬇️
plugins-hapi_hono_ioredis 55.89% <71.29%> (-5.20%) ⬇️
plugins-jest_knex_langgraph 51.86% <71.29%> (?)
plugins-jest_langgraph_ldapjs ?
plugins-ldapjs_light-my-request_limitd-client 53.59% <71.29%> (?)
plugins-light-my-request_limitd-client_lodash ?
plugins-lodash_mariadb_memcached 54.35% <71.29%> (?)
plugins-mariadb_memcached_mercurius ?
plugins-moleculer_mongodb_mongodb-core 57.42% <71.29%> (?)
plugins-mongodb_mongodb-core_mongoose ?
plugins-mongoose_multer_mysql 54.83% <71.29%> (?)
plugins-multer_mysql_mysql2 ?
plugins-mysql2_nats_node-serialize 56.36% <71.29%> (?)
plugins-nats_node-serialize_opensearch ?
plugins-opensearch_passport-http_pino 55.23% <71.29%> (?)
plugins-passport-http_pino_postgres ?
plugins-postgres_process_pug 54.42% <71.29%> (?)
plugins-process_pug_redis ?
plugins-redis_router_sequelize 57.19% <71.29%> (?)
plugins-test-and-upstream-rhea_undici_url 57.09% <71.29%> (?)
plugins-undici_url_valkey ?
plugins-valkey_vm_winston 53.99% <71.29%> (?)
plugins-vm_winston_ws ?
plugins-ws 54.97% <71.29%> (?)
profiling 58.27% <71.29%> (-4.78%) ⬇️
serverless-aws-sdk-aws-sdk 50.82% <71.29%> (-4.91%) ⬇️
serverless-aws-sdk-bedrockruntime 50.81% <71.29%> (-4.64%) ⬇️
serverless-aws-sdk-client 52.14% <71.29%> (-5.03%) ⬇️
serverless-aws-sdk-dynamodb 51.86% <71.29%> (-4.53%) ⬇️
serverless-aws-sdk-eventbridge 46.55% <71.29%> (-3.42%) ⬇️
serverless-aws-sdk-kinesis 54.82% <71.29%> (-5.32%) ⬇️
serverless-aws-sdk-lambda 52.92% <71.29%> (-5.22%) ⬇️
serverless-aws-sdk-s3 51.64% <71.29%> (-4.67%) ⬇️
serverless-aws-sdk-serverless-peer-service 54.85% <71.29%> (-5.71%) ⬇️
serverless-aws-sdk-sns 55.57% <71.29%> (-5.39%) ⬇️
serverless-aws-sdk-sqs 56.06% <71.29%> (-5.32%) ⬇️
serverless-aws-sdk-stepfunctions 51.41% <71.29%> (-4.88%) ⬇️
serverless-aws-sdk-util 48.64% <71.29%> (-3.59%) ⬇️
serverless-bucket-0 55.28% <71.29%> (+0.06%) ⬆️
serverless-bucket-1 56.09% <71.29%> (-3.99%) ⬇️
test-optimization-cucumber 72.92% <71.84%> (-0.10%) ⬇️
test-optimization-cypress 66.38% <66.01%> (-0.05%) ⬇️
test-optimization-jest 74.51% <78.70%> (+0.15%) ⬆️
test-optimization-mocha 74.66% <76.85%> (+0.02%) ⬆️
test-optimization-playwright-playwright-atr 61.43% <66.01%> (-0.01%) ⬇️
test-optimization-playwright-playwright-efd 61.62% <66.01%> (-0.02%) ⬇️
test-optimization-playwright-playwright-final-status 61.59% <66.01%> (-0.02%) ⬇️
test-optimization-playwright-playwright-impacted-tests 61.31% <66.01%> (-0.02%) ⬇️
test-optimization-playwright-playwright-reporting 61.20% <66.01%> (-0.02%) ⬇️
test-optimization-playwright-playwright-test-management 61.92% <66.01%> (-0.02%) ⬇️
test-optimization-playwright-playwright-test-span 61.29% <66.01%> (-0.07%) ⬇️
test-optimization-selenium 60.73% <66.01%> (+<0.01%) ⬆️
test-optimization-testopt 59.23% <71.29%> (+0.04%) ⬆️
test-optimization-vitest 71.24% <71.84%> (-0.15%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@leoromanovsky leoromanovsky changed the title feat(openfeature): make billed configuration sources opt-in feat(openfeature): default configuration delivery to agentless Jul 17, 2026
@pr-commenter

pr-commenter Bot commented Jul 18, 2026

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-07-21 03:25:22

Comparing candidate commit 94a16dc in PR branch leo.romanovsky/ffl-2697-nodejs-configuration-contract with baseline commit 053684d in branch leo.romanovsky/ffl-2697-nodejs-agentless-configuration-source.

📊 Benchmarking dashboard

Found 0 performance improvements and 0 performance regressions! Performance is the same for 2321 metrics, 37 unstable metrics.

Explanation

This is an A/B test comparing a candidate commit's performance against that of a baseline commit. Performance changes are noted in the tables below as:

  • 🟩 = significantly better candidate vs. baseline
  • 🟥 = significantly worse candidate vs. baseline

We compute a confidence interval (CI) over the relative difference of means between metrics from the candidate and baseline commits, considering the baseline as the reference.

If the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD), the change is considered significant.

Feel free to reach out to #apm-benchmarking-platform on Slack if you have any questions.

More details about the CI and significant changes

You can imagine this CI as a range of values that is likely to contain the true difference of means between the candidate and baseline commits.

CIs of the difference of means are often centered around 0%, because often changes are not that big:

---------------------------------(------|---^--------)-------------------------------->
                              -0.6%    0%  0.3%     +1.2%
                                 |          |        |
         lower bound of the CI --'          |        |
sample mean (center of the CI) -------------'        |
         upper bound of the CI ----------------------'

As described above, a change is considered significant if the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD).

For instance, for an execution time metric, this confidence interval indicates a significantly worse performance:

----------------------------------------|---------|---(---------^---------)---------->
                                       0%        1%  1.3%      2.2%      3.1%
                                                  |   |         |         |
       significant impact threshold --------------'   |         |         |
                      lower bound of CI --------------'         |         |
       sample mean (center of the CI) --------------------------'         |
                      upper bound of CI ----------------------------------'

Unstable benchmarks

These benchmarks have a confidence interval too wide to call a change; treat them as noise rather than signal.

scenario:appsec-appsec-enabled-24

  • unstable execution_time [-205.511ms; +219.484ms] or [-7.700%; +8.224%]

scenario:appsec-appsec-enabled-26

  • unstable execution_time [-238164.582µs; +238215.616µs] or [-9.336%; +9.338%]

scenario:appsec-appsec-enabled-with-attacks-24

  • unstable execution_time [-163308.159µs; +164803.959µs] or [-5.287%; +5.336%]

scenario:appsec-appsec-enabled-with-attacks-26

  • unstable execution_time [-190.610ms; +180.617ms] or [-6.559%; +6.215%]

scenario:appsec-control-20

  • unstable execution_time [-130.233ms; +127.442ms] or [-7.894%; +7.724%]

scenario:appsec-control-24

  • unstable execution_time [-117.542ms; +120.765ms] or [-9.481%; +9.741%]

scenario:appsec-control-26

  • unstable execution_time [-130.836ms; +110.767ms] or [-10.654%; +9.020%]

scenario:appsec-iast-no-vulnerability-control-20

  • unstable execution_time [-13.514ms; +15.639ms] or [-5.265%; +6.093%]

scenario:appsec-iast-no-vulnerability-iast-enabled-default-config-20

  • unstable execution_time [-12.297ms; +15.828ms] or [-4.731%; +6.090%]

scenario:debugger-line-probe-with-snapshot-default-24

  • unstable cpu_user_time [-2562.265ms; +2391.179ms] or [-29.035%; +27.096%]
  • unstable execution_time [-2563.915ms; +2386.911ms] or [-26.872%; +25.017%]
  • unstable instructions [-21900.5M instructions; +20472.6M instructions] or [-30.372%; +28.392%]
  • unstable max_rss_usage [-10580.555KB; +10034.155KB] or [-6.668%; +6.324%]
  • unstable throughput [-674.237op/s; +705.256op/s] or [-19.245%; +20.130%]

scenario:debugger-line-probe-with-snapshot-minimal-26

  • unstable cpu_user_time [-2279.809ms; +742.101ms] or [-23.889%; +7.776%]
  • unstable execution_time [-2296.149ms; +749.178ms] or [-22.375%; +7.300%]
  • unstable instructions [-20.3G instructions; +6.5G instructions] or [-25.556%; +8.212%]
  • unstable throughput [-150.124op/s; +453.202op/s] or [-4.648%; +14.033%]

scenario:debugger-line-probe-without-snapshot-24

  • unstable cpu_user_time [-1722.873ms; +2744.526ms] or [-20.849%; +33.213%]
  • unstable execution_time [-1740.820ms; +2769.638ms] or [-19.444%; +30.935%]
  • unstable instructions [-14.8G instructions; +23.6G instructions] or [-22.101%; +35.127%]
  • unstable max_rss_usage [-7.032MB; +11.661MB] or [-4.487%; +7.441%]
  • unstable throughput [-778.146op/s; +489.294op/s] or [-21.270%; +13.375%]

scenario:debugger-line-probe-without-snapshot-26

  • unstable cpu_user_time [-2673.729ms; +4170.123ms] or [-28.039%; +43.732%]
  • unstable execution_time [-2867.836ms; +4410.242ms] or [-27.893%; +42.895%]
  • unstable instructions [-23.1G instructions; +37.0G instructions] or [-29.049%; +46.511%]
  • unstable max_rss_usage [-8.794MB; +13.729MB] or [-5.520%; +8.618%]
  • unstable throughput [-839.822op/s; +561.957op/s] or [-25.962%; +17.372%]

scenario:dogstatsd-with-tags-20

  • unstable cpu_user_time [-410.786ms; +275.063ms] or [-8.388%; +5.617%]
  • unstable execution_time [-405.199ms; +274.431ms] or [-8.147%; +5.518%]
  • unstable throughput [-88368.906op/s; +142595.680op/s] or [-5.214%; +8.414%]

scenario:plugin-claude-agent-sdk-compact-stream-scan-26

  • unstable cpu_usage_percentage [-6.558%; +4.072%]

scenario:plugin-graphql-long-with-depth-off-26

  • unstable max_rss_usage [-23004.783KB; +21470.497KB] or [-10.582%; +9.876%]

scenario:plugin-graphql-long-with-depth-on-max-20

  • unstable cpu_user_time [-726.241ms; +688.741ms] or [-5.648%; +5.357%]
  • unstable execution_time [-731.334ms; +688.544ms] or [-5.566%; +5.240%]
  • unstable throughput [-3.151op/s; +3.358op/s] or [-5.145%; +5.484%]

scenario:test-optimization-large-suite-20

  • unstable max_rss_usage [-7.424MB; +4.234MB] or [-8.972%; +5.118%]

@leoromanovsky leoromanovsky changed the title feat(openfeature): default configuration delivery to agentless feat(openfeature): preserve configuration source semantics Jul 18, 2026
@leoromanovsky
leoromanovsky force-pushed the leo.romanovsky/ffl-2697-nodejs-configuration-contract branch from e9d4e43 to 4f57fe8 Compare July 20, 2026 17:11
@leoromanovsky

Copy link
Copy Markdown
Contributor Author

@codex Review this.

Focus on changes to start-up behavior to lazy init.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refines dd-trace-js OpenFeature Feature Flagging configuration-source precedence to preserve legacy Remote Config semantics while introducing a stable global enable switch and a lazy agentless (CDN) activation boundary tied to tracer.openfeature access, preventing unintended billed network traffic at tracer startup.

Changes:

  • Adds stable DD_FEATURE_FLAGS_ENABLED kill switch and updates configuration-source resolution to preserve legacy opt-in/out semantics when the new source is absent.
  • Makes agentless polling lazy by deferring provider construction and source startup until application code accesses tracer.openfeature.
  • Updates unit/integration tests to validate precedence, capability/RC subscription behavior, and new environment variables.

Reviewed changes

Copilot reviewed 12 out of 13 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/dd-trace/test/proxy.spec.js Updates proxy test wiring for OpenFeature RC enablement call signature.
packages/dd-trace/test/openfeature/remote_config.spec.js Updates RC unit tests to match new subscription/capability semantics.
packages/dd-trace/test/openfeature/register.spec.js Verifies lazy construction/activation boundary and updated RC hook invocation.
packages/dd-trace/test/openfeature/configuration_source.spec.js Adds coverage for stable kill switch + legacy/explicit-source precedence rules.
packages/dd-trace/test/config/index.spec.js Verifies config defaults/origins and env var parsing for the new stable switch.
packages/dd-trace/src/openfeature/remote_config.js Changes RC enablement to gate capability + handler registration on explicit subscription.
packages/dd-trace/src/openfeature/register.js Implements lazy provider exposure via getter and uses resolved source to decide RC subscription.
packages/dd-trace/src/openfeature/index.js Removes noisy debug log on module enable.
packages/dd-trace/src/openfeature/configuration_source.js Implements new resolution model (enabled + source) and stable kill switch behavior.
packages/dd-trace/src/config/supported-configurations.json Adds DD_FEATURE_FLAGS_ENABLED to supported configuration inventory.
packages/dd-trace/src/config/generated-config-types.d.ts Adds generated typing for DD_FEATURE_FLAGS_ENABLED.
integration-tests/openfeature/openfeature-exposure-events.spec.js Migrates integration tests to stable enable var while keeping RC source explicit.
integration-tests/openfeature/openfeature-agentless.spec.js Migrates agentless integration test env vars to stable enable var.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/dd-trace/test/proxy.spec.js
Comment thread packages/dd-trace/src/openfeature/configuration_source.js

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 23a9e2bb78

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/dd-trace/src/openfeature/register.js Outdated
@leoromanovsky
leoromanovsky marked this pull request as ready for review July 21, 2026 03:43
@leoromanovsky
leoromanovsky requested a review from a team as a code owner July 21, 2026 03:43
@leoromanovsky
leoromanovsky requested review from a team as code owners July 21, 2026 03:43
@leoromanovsky
leoromanovsky requested review from khanayan123, sameerank and typotter and removed request for a team July 21, 2026 03:43
@BridgeAR
BridgeAR force-pushed the leo.romanovsky/ffl-2697-nodejs-agentless-configuration-source branch from bd5962c to 8154935 Compare July 21, 2026 17:53
Comment thread index.d.ts
/**
* Whether to enable the feature flagging provider.
* Requires Remote Config to be properly configured.
* Can be configured via DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED environment variable.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this file needs more revising.

Would it be beneficial to mention DD_FEATURE_FLAGS_ENABLED to encourage the newer env variable instead? Also, is it worth documenting DD_FEATURE_FLAGS_CONFIGURATION_SOURCE here? Another place to add documentation about configuring the provider might be docs/API.md

Also the provider now defaults to enabled, and that legacy variable specifically selects Remote Config, so this might be confusing

dd-trace-js/index.d.ts

Lines 159 to 164 in 5b83654

* OpenFeature Provider with Remote Config integration.
*
* Extends DatadogNodeServerProvider with Remote Config integration for dynamic flag configuration.
* Enable with DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED=true.
*
* @env DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED

@typotter typotter left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed on documentation of the options/modes being super important here. other than that 🚀

env: {
DD_API_KEY: 'integration-api-key',
DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED: 'true',
DD_FEATURE_FLAGS_ENABLED: 'true',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀

@BridgeAR
BridgeAR force-pushed the leo.romanovsky/ffl-2697-nodejs-agentless-configuration-source branch from 8154935 to 05df5bd Compare July 21, 2026 20:48
@leoromanovsky

Copy link
Copy Markdown
Contributor Author

Handling this scope in #9397

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants